/*
 * db_mgr.h
 *
 *  Created on: Jan 9, 2014
 *      Author: killerg
 */

#ifndef DB_MGR_H_
#define DB_MGR_H_

#include <event2/event.h>
#include <libcouchbase/couchbase.h>
#include <functional>
#include "share/json/json.h"

enum db_error_t {
	DBE_Success = 0,
	DBE_Exist = 1,
	DBE_NoExist = 2,
	DBE_ArgsErr = 3,
	DBE_TryLater = 4,
	DBE_TryMoreLater = 5,
	DBE_CanNotRepair = 6,
};

const char* db_strerror(db_error_t err);

struct db_mgr_t {
    typedef std::function<void(db_error_t)> cb_e_t;
    typedef std::function<void(db_error_t, const Json::Value&)> cb_ej_t;
    typedef std::function<void(db_error_t, bool)> cb_eb_t;
    typedef std::function<void(db_error_t, const Json::Value&, bool)> cb_ejb_t;

    struct cookie_t {
        cb_e_t cb_e;
        cb_ej_t cb_ej;
        cb_eb_t cb_el;
        cb_ejb_t cb_ejb;
        int remain;
        cookie_t():remain(-1){}
    };

    enum EState{
    	Invalid = -1,
    	Initing = 0,
    	Running = 1,
    	Destroying = 2,
    };

    bool repair(int try_num = -1);
    bool ok() { return Running == _state; }
    lcb_error_t last_error() { return LCB_SUCCESS; }

    bool init(
            const std::string &host,
            const std::string &user,
            const std::string &passwd,
            const std::string &bucket);
    void destroy();
    void update();

    void wait();
    bool set(const char* key, const Json::Value &value, cb_e_t cb = NULL, time_t expire = 0) { return _store(key, value, cb, LCB_SET, expire); }
    bool add(const char* key, const Json::Value &value, cb_e_t cb = NULL, time_t expire = 0) { return _store(key, value, cb, LCB_ADD, expire); }
    bool dels(const std::vector<std::string> &keys, cb_eb_t cb);
    bool del(const char* key, cb_e_t cb = NULL);
    bool gets(const std::vector<std::string> &keys, cb_ejb_t cb);
    bool get(const char* key, cb_ej_t cb);
    bool view(const char* path, cb_ej_t cb);

    bool _store(const char* key, const Json::Value &value, cb_e_t cb, lcb_storage_t store_type, time_t expire);
    void create_instance();
    void destroy_instance();

    lcb_t _inst = NULL;
    lcb_io_opt_t ioops = NULL;
    event_base* base = NULL;

    EState _state = Invalid;

    std::string host;
    std::string user;
    std::string passwd;
    std::string bucket;

    bool finished = false;

    int32_t max_objsize = 0;
    int32_t min_objsize = 999999999;

    int32_t pending_get = 0;
    int32_t pending_gets = 0;
    int32_t pending_del = 0;
    int32_t pending_dels = 0;
    int32_t pending_add = 0;
    int32_t pending_set = 0;
    int32_t pending_view = 0;
    int32_t pending_conf = 0;
    int32_t operating = 0;

    bool has_pending() {
        return pending_get + pending_gets + pending_del + pending_dels+ pending_add + pending_set + pending_view > 0;
    }
};
#endif /* DB_MGR_H_ */
